Разгледайте мощните типове шаблонни литерали на TypeScript за усъвършенствана манипулация на низове, съпоставяне на модели и валидиране. Научете с практически примери и реални случаи на употреба.
Типове шаблонни литерали: Съпоставяне и валидиране на низови модели в TypeScript
Типовата система на TypeScript непрекъснато се развива, предлагайки на разработчиците по-мощни инструменти за изразяване на сложна логика и осигуряване на безопасност на типовете. Една от най-интересните и гъвкави функции, въведени в последните версии, са типовете шаблонни литерали. Тези типове ви позволяват да манипулирате низове на ниво тип, което позволява усъвършенствано съпоставяне и валидиране на низови модели. Това отваря цял нов свят от възможности за създаване на по-стабилни и лесни за поддръжка приложения.
Какво представляват типовете шаблонни литерали?
Типовете шаблонни литерали са форма на тип, който е конструиран чрез комбиниране на типове низови литерали и обединени типове, подобно на това как шаблонните литерали работят в JavaScript. Въпреки това, вместо да създават низове по време на изпълнение, те създават нови типове въз основа на съществуващи такива.
Ето един основен пример:
type Greeting<T extends string> = `Hello, ${T}!`;
type MyGreeting = Greeting<"World">; // type MyGreeting = "Hello, World!"
В този пример `Greeting` е тип шаблонен литерал, който приема тип низ `T` като вход и връща нов тип, който е конкатенацията на "Hello, ", `T` и "!".
Основно съпоставяне на низови модели
Типовете шаблонни литерали могат да се използват за извършване на основно съпоставяне на низови модели. Това ви позволява да създавате типове, които са валидни само ако съвпадат с определен модел.
Например, можете да създадете тип, който приема само низове, които започват с "prefix-":
type PrefixedString<T extends string> = T extends `prefix-${string}` ? T : never;
type ValidPrefixedString = PrefixedString<"prefix-valid">; // type ValidPrefixedString = "prefix-valid"
type InvalidPrefixedString = PrefixedString<"invalid">; // type InvalidPrefixedString = never
В този пример `PrefixedString` използва условен тип, за да провери дали входният низ `T` започва с "prefix-". Ако да, типът е самият `T`; в противен случай е `never`. `never` е специален тип в TypeScript, който представлява типа на стойностите, които никога не се срещат, като ефективно изключва невалидния низ.
Извличане на части от низ
Типовете шаблонни литерали могат също да се използват за извличане на части от низ. Това е особено полезно, когато трябва да анализирате данни от низове и да ги конвертирате в различни типове.
Да кажем, че имате низ, който представлява координата във формата "x:10,y:20". Можете да използвате типове шаблонни литерали, за да извлечете x и y стойностите:
type CoordinateString = `x:${number},y:${number}`;
type ExtractX<T extends CoordinateString> = T extends `x:${infer X},y:${number}` ? X : never;
type ExtractY<T extends CoordinateString> = T extends `x:${number},y:${infer Y}` ? Y : never;
type XValue = ExtractX<"x:10,y:20">; // type XValue = 10
type YValue = ExtractY<"x:10,y:20">; // type YValue = 20
В този пример `ExtractX` и `ExtractY` използват ключовата дума `infer`, за да уловят частите от низа, които съвпадат с типа `number`. `infer` ви позволява да извлечете тип от съвпадение на модел. Захваналите типове след това се използват като тип на връщане на условния тип.
Разширено валидиране на низове
Типовете шаблонни литерали могат да бъдат комбинирани с други функции на TypeScript, като например обединени типове и условни типове, за да се извърши разширено валидиране на низове. Това ви позволява да създавате типове, които налагат сложни правила за структурата и съдържанието на низовете.
Например, можете да създадете тип, който валидира ISO 8601 низове за дата:
type Year = `${number}${number}${number}${number}`;
type Month = `0${number}` | `10` | `11` | `12`;
type Day = `${0}${number}` | `${1 | 2}${number}` | `30` | `31`;
type ISODate = `${Year}-${Month}-${Day}`;
type ValidDate = ISODate extends "2023-10-27" ? true : false; // true
type InvalidDate = ISODate extends "2023-13-27" ? true : false; // false
function processDate(date: ISODate) {
// Function logic here. TypeScript enforces the ISODate format.
return `Processing date: ${date}`;
}
console.log(processDate("2024-01-15")); // Works
//console.log(processDate("2024-1-15")); // TypeScript error: Argument of type '"2024-1-15"' is not assignable to parameter of type '`${number}${number}${number}${number}-${0}${number}-${0}${number}` | `${number}${number}${number}${number}-${0}${number}-${1}${number}` | ... 14 more ... | `${number}${number}${number}${number}-12-31`'.
Тук `Year`, `Month` и `Day` са дефинирани с помощта на типове шаблонни литерали, за да представят валидните формати за всяка част от датата. След това `ISODate` комбинира тези типове, за да създаде тип, който представлява валиден ISO 8601 низ за дата. Примерът също така демонстрира как този тип може да се използва за налагане на форматиране на данни във функция, предотвратявайки предаването на неправилни формати на дата. Това подобрява надеждността на кода и предотвратява грешки по време на изпълнение, причинени от невалиден вход.
Реални случаи на употреба
Типовете шаблонни литерали могат да се използват в различни реални сценарии. Ето няколко примера:
- Валидиране на формуляри: Можете да използвате типове шаблонни литерали, за да валидирате формата на входните данни във формулярите, като например имейл адреси, телефонни номера и пощенски кодове.
- Валидиране на API заявки: Можете да използвате типове шаблонни литерали, за да валидирате структурата на полезните данни на API заявките, като гарантирате, че те отговарят на очаквания формат. Например, валидиране на код на валута (напр. "USD", "EUR", "GBP").
- Анализиране на конфигурационни файлове: Можете да използвате типове шаблонни литерали, за да анализирате конфигурационни файлове и да извличате стойности въз основа на конкретни модели. Помислете за валидиране на пътища на файлове в конфигурационен обект.
- Базирани на низове изброявания: Можете да създадете базирани на низове изброявания с валидиране, като използвате типове шаблонни литерали.
Пример: Валидиране на кодове на валути
Нека разгледаме по-подробен пример за валидиране на кодове на валути. Искаме да гарантираме, че в нашето приложение се използват само валидни ISO 4217 кодове на валути. Тези кодове обикновено са три главни букви.
type CurrencyCode = `${Uppercase<string>}${Uppercase<string>}${Uppercase<string>}`;
function formatCurrency(amount: number, currency: CurrencyCode) {
// Function logic to format currency based on the provided code.
return `$${amount} ${currency}`;
}
console.log(formatCurrency(100, "USD")); // Works
//console.log(formatCurrency(100, "usd")); // TypeScript error: Argument of type '"usd"' is not assignable to parameter of type '`${Uppercase}${Uppercase}${Uppercase}`'.
//More precise example:
type ValidCurrencyCode = "USD" | "EUR" | "GBP" | "JPY" | "CAD" | "AUD"; // Extend as needed
type StronglyTypedCurrencyCode = ValidCurrencyCode;
function formatCurrencyStronglyTyped(amount: number, currency: StronglyTypedCurrencyCode) {
return `$${amount} ${currency}`;
}
console.log(formatCurrencyStronglyTyped(100, "EUR")); // Works
//console.log(formatCurrencyStronglyTyped(100, "CNY")); // TypeScript error: Argument of type '"CNY"' is not assignable to parameter of type '"USD" | "EUR" | "GBP" | "JPY" | "CAD" | "AUD"'.
Този пример демонстрира как да създадете тип `CurrencyCode`, който приема само низове, състоящи се от три главни знака. Вторият, по-силно типизиран пример показва как да ограничите това още повече до предварително дефиниран списък от приемливи валути.
Пример: Валидиране на пътища на API крайни точки
Друг случай на употреба е валидирането на пътища на API крайни точки. Можете да дефинирате тип, който представлява валидна структура на API крайна точка, като гарантирате, че заявките се правят към правилните пътища. Това е особено полезно в микросервизни архитектури, където множество услуги могат да излагат различни API.
type APIServiceName = "users" | "products" | "orders";
type APIEndpointPath = `/${APIServiceName}/${string}`;
function callAPI(path: APIEndpointPath) {
// API call logic
console.log(`Calling API: ${path}`)
}
callAPI("/users/123"); // Valid
callAPI("/products/details"); // Valid
//callAPI("/invalid/path"); // TypeScript error
// Even more specific:
type APIAction = "create" | "read" | "update" | "delete";
type APIEndpointPathSpecific = `/${APIServiceName}/${APIAction}`;
function callAPISpecific(path: APIEndpointPathSpecific) {
// API call logic
console.log(`Calling specific API: ${path}`)
}
callAPISpecific("/users/create"); // Valid
//callAPISpecific("/users/list"); // TypeScript error
Това ви позволява да дефинирате структурата на API крайните точки по-прецизно, предотвратявайки печатни грешки и осигурявайки последователност в цялото ви приложение. Това е основен пример; могат да бъдат създадени по-сложни модели за валидиране на параметри на заявки и други части от URL адреса.
Предимства от използването на типове шаблонни литерали
Използването на типове шаблонни литерали за съпоставяне и валидиране на низови модели предлага няколко предимства:
- Подобрена безопасност на типовете: Типовете шаблонни литерали ви позволяват да налагате по-строги ограничения на типовете върху низовете, намалявайки риска от грешки по време на изпълнение.
- Подобрена четимост на кода: Типовете шаблонни литерали правят кода ви по-четлив, като ясно изразяват очаквания формат на низовете.
- Повишена поддръжка: Типовете шаблонни литерали правят кода ви по-лесен за поддръжка, като предоставят единствен източник на истина за правилата за валидиране на низове.
- По-добро разработчиково изживяване: Типовете шаблонни литерали осигуряват по-добро автоматично довършване и съобщения за грешки, подобрявайки цялостното разработчиково изживяване.
Ограничения
Въпреки че типовете шаблонни литерали са мощни, те също имат някои ограничения:
- Сложност: Типовете шаблонни литерали могат да станат сложни, особено когато се работи със сложни модели. От решаващо значение е да се балансират ползите от безопасността на типовете с поддръжката на кода.
- Производителност: Типовете шаблонни литерали могат да повлияят на производителността на компилация, особено в големи проекти. Това е така, защото TypeScript трябва да извърши по-сложна проверка на типовете.
- Ограничена поддръжка на регулярни изрази: Въпреки че типовете шаблонни литерали позволяват съпоставяне на модели, те не поддържат пълната гама от функции на регулярни изрази. За силно сложно валидиране на низове може да са необходими регулярни изрази по време на изпълнение заедно с тези типови конструкции за правилно почистване на входните данни.
Най-добри практики
Ето някои най-добри практики, които трябва да имате предвид, когато използвате типове шаблонни литерали:
- Започнете просто: Започнете с прости модели и постепенно увеличавайте сложността, ако е необходимо.
- Използвайте описателни имена: Използвайте описателни имена за вашите типове шаблонни литерали, за да подобрите четимостта на кода.
- Документирайте вашите типове: Документирайте вашите типове шаблонни литерали, за да обясните тяхната цел и употреба.
- Тествайте внимателно: Тествайте старателно вашите типове шаблонни литерали, за да се уверите, че се държат според очакванията.
- Обърнете внимание на производителността: Бъдете внимателни към въздействието на типовете шаблонни литерали върху производителността на компилация и оптимизирайте кода си по съответния начин.
Заключение
Типовете шаблонни литерали са мощна функция в TypeScript, която ви позволява да извършвате разширена манипулация на низове, съпоставяне на модели и валидиране на ниво тип. Използвайки типове шаблонни литерали, можете да създадете по-стабилни, лесни за поддръжка и безопасни за типовете приложения. Въпреки че имат някои ограничения, ползите от използването на типове шаблонни литерали често надвишават недостатъците, което ги прави ценен инструмент в арсенала на всеки разработчик на TypeScript. Тъй като езикът TypeScript продължава да се развива, разбирането и използването на тези разширени типови функции ще бъде от решаващо значение за създаването на висококачествен софтуер. Не забравяйте да балансирате сложността с четимостта и винаги да давате приоритет на задълбоченото тестване.